namespace bt {
    /**
     * 装饰节点基类
     *
     * @export
     * @class Decorator
     * @extends {BaseNode}
     */
    export class Decorator extends BaseNode {
        constructor(params: any) {
            super(params);
            params = params || {};
            this.category = CategoryType.DECORATOR;
            this.name = 'Decorator';
            this.child = params.child || null;
        }
    }

    /**
     * 反转节点
     *
     * @export
     * @class Inverter
     * @extends {Decorator}
     */
    export class Inverter extends Decorator {
        constructor(params?: any) {
            super(params);
            this.name = 'Inverter';
        }
    
        tick(tick: Tick) : ActionStatus {
            if (!this.child) {
                return ActionStatus.ERROR;
            }
            let status = this.child._execute(tick);
            if (status === ActionStatus.SUCCESS) {
                status = ActionStatus.FAILURE;
            } else if (status === ActionStatus.FAILURE) {
                status = ActionStatus.SUCCESS;
            }
            return status;
        }
    }

    /**
     * 限制最大循环
     *
     * @export
     * @class Limiter
     * @extends {Decorator}
     */
    export class Limiter extends Decorator {
        maxLoop: number = 1;
        constructor(params?: any) {
            super(params);
            params = params || {maxLoop: 1};
            this.name = 'Limiter';
            this.title = 'Limit <maxLoop> Activations';
            this.properties = params
            this.maxLoop = params.maxLoop || 1;
        }
    
        open(tick: Tick) {
            let i = tick.blackboard.get('i', tick.tree.id, this.id);
            if (!i) {
                i = 0;
            }
            tick.blackboard.set('i', i, tick.tree.id, this.id);
        
        }
    
        tick(tick: Tick) : ActionStatus {
            if (!this.child) {
                return ActionStatus.ERROR;
            }
            let i = tick.blackboard.get('i', tick.tree.id, this.id);
            if (i < this.maxLoop) {
                let status = this.child._execute(tick);
                if (status === ActionStatus.SUCCESS || status === ActionStatus.FAILURE) {
                    tick.blackboard.set('i', i + 1, tick.tree.id, this.id);
                }
                return status;
            }
            return ActionStatus.FAILURE;
        }
    }

    /**
     * 限制最大时间
     *
     * @export
     * @class MaxTime
     * @extends {Decorator}
     */
    export class MaxTime extends Decorator {
        maxTime: number = 0;
        constructor(params?: any) {
            super(params);
            params = params || {maxTime: 0};
            this.name = 'MaxTime';
            this.title = 'Max <maxTime>ms';
            this.properties = params
            this.maxTime = params.maxTime || 0;
        }
    
        open(tick: Tick) {
            let startTime = (new Date()).getTime();
            tick.blackboard.set('startTime', startTime, tick.tree.id, this.id);
        }
    
        tick(tick: Tick) : ActionStatus {
            if (!this.child) {
                return ActionStatus.ERROR;
            }
            let currentTime = (new Date()).getTime();
            let startTime = tick.blackboard.get('startTime', tick.tree.id, this.id);
            let status = this.child._execute(tick);
            if (currentTime - startTime > this.maxTime) {
                return ActionStatus.FAILURE;
            }
            return status;
        }
    }

    /**
     * 循环
     *
     * @export
     * @class Repeater
     * @extends {Decorator}
     */
    export class Repeater extends Decorator {
        maxLoop: number;
        constructor(params?: any) {
            super(params);
            params = params || {maxLoop: -1};
            this.name = 'Repeater';
            this.title = 'Repeat <maxLoop>x';
            this.properties = params
            this.maxLoop = params.maxLoop || -1;
        }
    
        open(tick: Tick) {
            tick.blackboard.set('i', 0, tick.tree.id, this.id);
        }
    
        tick(tick: Tick) : ActionStatus {
            if (!this.child) {
                return ActionStatus.ERROR;
            }
            let i = tick.blackboard.get('i', tick.tree.id, this.id);
            let status = ActionStatus.SUCCESS;
            while(this.maxLoop < 0 || i < this.maxLoop) {
                status = this.child._execute(tick);
                if (status === ActionStatus.SUCCESS || status === ActionStatus.FAILURE) {
                    i++;
                } else {
                    break;
                }
            }
            tick.blackboard.set('i', i, tick.tree.id, this.id);
            return status;
        }
    }

    /**
     * 循环知道失败
     *
     * @export
     * @class RepeatUntilFailure
     * @extends {Decorator}
     */
    export class RepeatUntilFailure extends Decorator {
        maxLoop: number = -1;
        constructor(params?: any) {
            super(params);
            params = params || {maxLoop: -1};
            this.name = 'RepeatUntilFailure';
            this.title = 'Repeat Until Failure';
            this.properties = params
            this.maxLoop = params.maxLoop || -1;
        }
    
        open(tick: Tick) {
            tick.blackboard.set('i', 0, tick.tree.id, this.id);
        }
    
        tick(tick: Tick) : ActionStatus {
            if (!this.child) {
                return ActionStatus.ERROR;
            }
            let i = tick.blackboard.get('i', tick.tree.id, this.id);
            let status = ActionStatus.ERROR;
            while(this.maxLoop < 0 || i < this.maxLoop) {
                status = this.child._execute(tick);
                if (status === ActionStatus.SUCCESS) {
                    i++;
                } else {
                    break;
                }
            }
            tick.blackboard.set('i', i, tick.tree.id, this.id);
            return status;
        }
    }

    /**
     * 循环直到成功
     *
     * @export
     * @class RepeatUntilSuccess
     * @extends {Decorator}
     */
    export class RepeatUntilSuccess extends Decorator {
        maxLoop: number = -1;
        constructor(params?: any) {
            super(params);
            params = params || {maxLoop: -1};
            this.name = 'RepeatUntilSuccess';
            this.title = 'Repeat Until Success';
            this.properties = params
            this.maxLoop = params.maxLoop || -1;
        }
    
        open(tick: Tick) {
            tick.blackboard.set('i', 0, tick.tree.id, this.id);
        }
    
        tick(tick: Tick) : ActionStatus {
            if (!this.child) {
                return ActionStatus.ERROR;
            }
            let i = tick.blackboard.get('i', tick.tree.id, this.id);
            let status = ActionStatus.ERROR;
            while(this.maxLoop < 0 || i < this.maxLoop) {
                status = this.child._execute(tick);
                if (status === ActionStatus.FAILURE) {
                    i++;
                } else {
                    break;
                }
            }
            tick.blackboard.set('i', i, tick.tree.id, this.id);
            return status;
        }
    }
}